package com.gitee.wsl.common.chart.sample.bar

import android.graphics.Canvas
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.render.background.axis.line.CategoryLineAxis
import com.gitee.wsl.common.chart.render.background.axis.line.DataLineAxis
import com.gitee.wsl.common.chart.render.shape.bar.Bar
import com.gitee.wsl.common.chart.render.shape.bar.Bar3D
import com.gitee.wsl.common.chart.sample.bar.model.BarData
import com.gitee.wsl.common.ui.draw.type.GridDirection
import com.gitee.wsl.android.ui.ext.type.textHeight
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.add
import com.gitee.wsl.jvm.math.div
import com.gitee.wsl.jvm.math.mul
import com.gitee.wsl.jvm.math.sub

import timber.log.Timber


/**
 * @ClassName Bar3DChart
 * @Description  3D柱形图的基类,包含横向和竖向3D柱形图
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */

class BarChart3D:BarChart(){
    //3D柱形绘制
    val bar3D = Bar3D()

    /*fun BarChart3D() {
        if (null != categoryAxis) categoryAxis.hideTickMarks()
        setBarCenterStyle(ChartEnum.BarCenterStyle.TICKMARKS)
    }*/

    override fun getType(): ChartEnum.ChartType {
        return ChartEnum.ChartType.BAR3D
    }

    /**
     * 设置坐标系底座厚度
     * @param thickness 底座厚度
     */
    fun setAxis3DBaseThickness(thickness: Float) {
        bar3D.axisBaseThickness = thickness
    }

    /**
     * 返回坐标系底座厚度
     * @return 底座厚度
     */
    fun getAxis3DBaseThickness(): Float {
        return bar3D.axisBaseThickness
    }

    /**
     * 设置柱形3D厚度
     * @param thickness 厚度
     */
    fun setBarThickness(thickness: Float) {
        bar3D.thickness = thickness
    }

    /**
     * 返回柱形3D厚度
     * @return 厚度
     */
    fun getBarThickness(): Float {
        return bar3D.thickness
    }

    /**
     * 设置3D偏转角度
     * @param angle 角度
     */
    fun setBarAngle(angle: Float) {
        bar3D.angle = angle
    }

    /**
     * 返回3D偏转角度
     * @return 角度
     */
    fun getBarAngle(): Float {
        return bar3D.angle
    }

    /**
     * 设透明度
     * @param alpha 透明度
     */
    fun setBarAlpha(alpha: Int) {
        bar3D.alpha = alpha
    }

    /**
     * 坐标基座颜色
     * @param color 颜色
     */
    fun setAxis3DBaseColor(color: Int) {
        bar3D.axisBaseColor = color
    }

    fun getBar(): Bar {
        return bar3D
    }


     override fun drawHorizontalBar(canvas: Canvas, dataAxis: DataLineAxis, categoryAxis: CategoryLineAxis): Boolean {
        //得到数据源
        val chartDataSource: List<BarData> = this.dataSet
        if (chartDataSource.isEmpty()) return false

        //得到Y 轴分类横向间距高度
        val YSteps = getVerticalYSteps(getCateTickCount(categoryAxis)) //getHorizontalYSteps();	
        val barInitX: Float = bodyViewport.left + moveX
        val barInitY: Float = bodyViewport.bottom // + this.mMoveY;


        //依柱形宽度，多柱形间的偏移值 与当前数据集的总数据个数得到当前分类柱形要占的高度	
        val barNumber = getDatasetSize(chartDataSource,dataAxis)
        if (barNumber <= 0) return false
        var currNumber = 0
        val ret = bar3D.getBarHeightAndMargin(YSteps, barNumber)
        if (null == ret || ret.size != 2) {
            Timber.d( "分隔间距计算失败.")
            return false
        }
        val barHeight = ret[0]
        val barInnerMargin = ret[1]
        val labelBarUseHeight: Float = Math.add(
            Math.mul(barNumber.toFloat(), barHeight),
            Math.mul((barNumber - 1).toFloat(), barInnerMargin)
        )
        val scrWidth: Float = bodyViewport.width//plotArea.getWidth();
        val valueWidth: Float = dataAxis.axisRange
        for (i in 0 until barNumber) {
            //得到分类对应的值数据集
            val bd = chartDataSource[i]
            val barValues = bd.dataSet
            if (barValues.size == 0) continue
            val barDataColor = bd.dataColor
            //设置成对应的颜色	
            val barDefualtColor = bd.color
            bar3D.barPaint.color = barDefualtColor

            //画同分类下的所有柱形
            for (j in barValues.indices) {
                val bv = barValues[j]
                setBarDataColor(bar3D.barPaint, barDataColor, j, barDefualtColor)
                var drawBarButtomY: Float = Math.add(
                    Math.sub(barInitY, Math.mul((j + 1).toFloat(), YSteps)),
                    labelBarUseHeight / 2
                )
                drawBarButtomY = Math.sub(drawBarButtomY, (barHeight + barInnerMargin) * currNumber)

                //参数值与最大值的比例  照搬到 y轴高度与矩形高度的比例上来
                val tlen = Math.sub(bv, dataAxis.axisMin)
                val valuePostion: Float = Math.mul(scrWidth, Math.div(tlen, valueWidth))

                //画出柱形                	 	
                val topY: Float = Math.sub(drawBarButtomY, barHeight)
                val rightX: Float = Math.add(barInitX, valuePostion)
                bar3D.renderHorizontal3DBar(
                    barInitX,
                    topY, rightX, drawBarButtomY,
                    bar3D.barPaint.color, canvas
                )

                //保存位置
                saveBarRectFRecord(
                    i, j, barInitX + moveX,
                    topY + moveY, rightX + moveX, drawBarButtomY + moveY
                )
                val labelTopY: Float = Math.sub(drawBarButtomY, barHeight / 2)

                //在柱形的顶端显示上批注形状
                drawAnchor(this.anchorSet, i, j, canvas, rightX, labelTopY, 0.0f)

                //在柱形的顶端显示上柱形的当前值	  
                if (!isEqualAxisMin && dataAxis.axisMin.compareTo(bv) == 0) {
                } else {
                    bar3D.renderBarItemLabel(getFormatterItemLabel(bv), rightX, labelTopY, canvas)
                }
            }
            currNumber++
        }
        return true
    }

    override fun get3DOffsetX(): Float // 分类		
    {
        return (bar3D.offsetX * 2).toFloat()
    }

    override fun get3DBaseOffsetX(): Float // 分类		
    {
        val baseTickness = bar3D.axisBaseThickness
        val baseAngle = bar3D.angle
        val baseOffsetX = bar3D.getOffsetX(baseTickness, baseAngle)
        return baseOffsetX
    }

     fun get3DBaseOffsetY(categoryAxis: CategoryLineAxis): Float // 分类
    {
        //3D 偏移值		
        val baseTickness = bar3D.axisBaseThickness
        val baseAngle = bar3D.angle
        //double baseOffsetX = mBar3D.getOffsetX(baseTickness,baseAngle);
        val baseOffsetY = bar3D.getOffsetY(baseTickness, baseAngle)
        val labelHeight =  categoryAxis.tickLabelPaint.textHeight
        
        // 画上分类/刻度线
        val th = Math.add(Math.add(baseOffsetY, baseTickness), labelHeight)
        return th
    }

     override fun drawVerticalBar(canvas: Canvas, dataAxis: DataLineAxis, categoryAxis: CategoryLineAxis): Boolean {
        //分类轴(X 轴) 且在这画柱形    		 
        val barInitX: Float = bodyViewport.left
        val barInitY: Float = bodyViewport.bottom

        //得到分类轴数据集
        val dataSet: List<String> = categoryAxis.dataSet
        if ( dataSet.isEmpty()) return false

        // 依传入的分类个数与轴总宽度算出要画的分类间距数是多少
        // 总宽度 / 分类个数 = 间距长度					
        val XSteps: Float = Math.div(bodyViewport.width, (dataSet.size + 1).toFloat())


        //得到数据源
        val chartDataSource: List<BarData> = this.dataSet
        if ( chartDataSource.isEmpty()) return false
        val barNumber = getDatasetSize(chartDataSource,dataAxis)
        if (barNumber <= 0) return false
        var currNumber = 0
        val ret = bar3D.getBarWidthAndMargin(XSteps, barNumber)
        if (null == ret || ret.size != 2) {
            Timber.d( "分隔间距计算失败.")
            return false
        }
        val barWidth = ret[0]
        val barInnerMargin = ret[1]
        val labelBarUseWidth: Float = Math.add(
            Math.mul(barNumber.toFloat(), barWidth),
            Math.mul((barNumber - 1).toFloat(), barInnerMargin)
        )
        val axisRange: Float = dataAxis.axisRange
        val axisMin: Float = dataAxis.axisMin

        //开始处 X 轴 即分类轴                  
        for (i in 0 until barNumber) {
            //依初超始X坐标与分类间距算出当前刻度的X坐标
            //float currentX = add(barInitX, mul((i+1), XSteps) );

            //得到分类对应的值数据集				
            val bd = chartDataSource[i]
            val barValues = bd.dataSet
            val barDataColor = bd.dataColor
            //设成对应的颜色
            val barDefualtColor = bd.color
            bar3D.barPaint.color = barDefualtColor

            //画出分类下的所有柱形
            for (j in barValues.indices) {
                val bv = barValues[j]
                setBarDataColor(bar3D.barPaint, barDataColor, j, barDefualtColor)

                //参数值与最大值的比例  照搬到 y轴高度与矩形高度的比例上来					   
                val tlen = Math.sub(bv, axisMin)
                var valuePostion = Math.div(tlen, axisRange)
                valuePostion = Math.mul(bodyViewport.height, valuePostion)

                //计算同分类多柱 形时，新柱形的起始X坐标
                var drawBarStartX: Float = Math.sub(Math.add(barInitX, Math.mul((j + 1).toFloat(), XSteps)), labelBarUseWidth / 2)
                drawBarStartX = Math.add(drawBarStartX, (barWidth + barInnerMargin) * currNumber)

                //计算同分类多柱 形时，新柱形的结束X坐标
                val drawBarEndX: Float = Math.add(drawBarStartX, barWidth)

                //画出柱形      
                val topY: Float = Math.sub(barInitY, valuePostion)
                bar3D.renderVertical3DBar(
                    drawBarStartX, topY,
                    drawBarEndX, barInitY,
                    bar3D.barPaint.color, canvas
                )

                //保存位置
                saveBarRectFRecord(
                    i, j, drawBarStartX + moveX, topY + moveY,
                    drawBarEndX + moveX, bodyViewport.bottom + moveY
                )
                val labelTopX: Float = Math.add(drawBarStartX, barWidth / 2)

                //在柱形的顶端显示上批注形状
                drawAnchor(anchorSet, i, j, canvas, labelTopX, topY, 0.0f)

                //在柱形的顶端显示上柱形的当前值
                bar3D.renderBarItemLabel(getFormatterItemLabel(bv), labelTopX, topY, canvas)

                //显示焦点框
                drawFocusRect(canvas, i, j, drawBarStartX, topY, drawBarEndX, barInitY)
            }
            currNumber++
        }
        return true
    }


     override fun drawClipAxisLine(canvas: Canvas) {
        when (gridDirection) {
            GridDirection.HORIZONTAL -> {
                //x轴 线 [要向里突]
                dataAxis.renderAxis(
                    canvas, bodyViewport.left, bodyViewport.bottom,
                    bodyViewport.right, bodyViewport.bottom
                )

                //Y轴线
                bar3D.render3DYAxis(
                    bodyViewport.left, bodyViewport.top,
                    bodyViewport.right, bodyViewport.bottom, canvas
                )
            }
            GridDirection.VERTICAL -> {
                dataAxis.renderAxis(
                    canvas, bodyViewport.left, bodyViewport.top,
                    bodyViewport.left, bodyViewport.bottom
                )

                //X轴 线
                bar3D.render3DXAxis(
                    bodyViewport.left, bodyViewport.bottom,
                    bodyViewport.right, bodyViewport.bottom, canvas
                )
            }
        }
    }
}